package org.dreamwork.peony;

import org.dreamwork.util.ICollection;
import org.dreamwork.util.IDataCollection;
import org.dreamwork.util.IDataList;

import java.util.*;
import java.util.regex.Pattern;

/**
 * Created by IntelliJ IDEA.
 * User: seth
 * Date: 2009-1-21
 * Time: 13:26:01
 */
public class DataBinder {
//    private static final Object[] args = {};
    private static final Pattern pattern = Pattern.compile ("^[\\d]+$");

    private static boolean isNumber (String string) {
        return pattern.matcher (string).matches ();
    }

    public static List parseDataSource (Object dataSource, String dataMember) {
        if (dataMember != null) {
            Object obj = eval (dataSource, dataMember);
            return parseDataSource (obj);
        } else {
            return parseDataSource (dataSource);
        }
    }

    public static List parseDataSource (Object dataSource) {
        if (dataSource instanceof List)
            return (List) dataSource;
        if (dataSource instanceof IDataList)
            return ((IDataList) dataSource).getData ();
        if (dataSource instanceof IDataCollection)
            return ((IDataCollection) dataSource).getData ();
        if (dataSource instanceof Collection<?>) {
            List<Object> list = new ArrayList<Object> ();
            list.addAll ((Collection<?>) dataSource);
            return list;
        } if (dataSource instanceof ICollection) {
            List<Object> list = new ArrayList<Object> ();
            ICollection c = (ICollection) dataSource;
            for (int i = 0; i < c.count (); i ++)
                list.add (c.get (i));
            return list;
        }
        if (dataSource instanceof Object[])
            return Arrays.asList ((Object[]) dataSource);

        return null;
    }

    public static Object eval (Object container, String expression) {
        if ("this".equalsIgnoreCase (expression) || ".".equals (expression)) return container;
        try {
            return getValueFromObject (container, expression);
        } catch (BindingException ex) {
            throw new RuntimeException (ex);
        }
    }

    public static String eval (Object container, String expression, String pattern) {
        Object value = eval (container, expression);
        return Formatter.format (value, pattern); 
    }

    private static Object getValueFromObject (Object container, String expression) throws BindingException {
        if (container == null) return null;
        String[] parts = expression.split ("\\.");
        Object current = container;
        for (String propName : parts) {
			if (current == null) return null;
            if (propName.charAt (0) == '[') {
                propName = propName.substring (1, propName.length () - 1);
                if (!isNumber (propName)) {
                    if (propName.charAt (0) == '\'' || propName.charAt (0) == '"')
                        propName = propName.substring (1, propName.length () - 1);
                    if (current instanceof Map) current = ((Map) current).get (propName);
                    else throw new BindingException ("Unknown expression " + propName);
                } else {
                    int index = Integer.parseInt (propName);
                    if (current instanceof List) current = ((List) current).get (index);
                    else if (current instanceof Object[]) current = ((Object[]) current)[index];
                    else throw new BindingException ("Unknown expression " + propName);
                }
            } else {
                if (current instanceof Map) {
                    current = ((Map) current).get (propName);
                } else {
                    try {
                        current = org.dreamwork.util.ReferenceUtil.get (current, propName);
//                        PropertyDescriptor pd = new PropertyDescriptor (propName, current.getClass ());
//                        Method method = pd.getReadMethod ();
//                        if (method != null)
//                            method.setAccessible(true);
//                        current = method.invoke (current, args);
/*
                        ReflectionUtil ru = new ReflectionUtil (current);
                        current = ru.getValue (propName);
*/
/*
                    } catch (IntrospectionException ie) {
                        return null;
*/
                    } catch (Exception ex) {
                        throw new BindingException (ex);
                    }
                }
            }
        }

        return current;
    }
}